home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / choices / chcssml1.lha / Process.c < prev    next >
C/C++ Source or Header  |  1989-02-06  |  7KB  |  293 lines

  1. /*
  2.  * This file is part of the Choices Operating System Simulator
  3.  * Developed by: The TAPESTRY Parallel Computing Laboratory
  4.  *         University of Illinois at Urbana-Champaign
  5.  *         Department of Computer Science
  6.  *         1304 W. Springfield Ave.
  7.  *         Urbana, IL    61801
  8.  *
  9.  * Copyright (c) 1987, 1988, 1989 The University of Illinois Board of Trustees.
  10.  *    All Rights Reserved.
  11.  * CONFIDENTIAL INFORMATION. Distribution restricted under license agreement.
  12.  *
  13.  * Author: Gary M. Johnston (johnston@cs.uiuc.edu)
  14.  * Project Manager and Principal Investigator: Roy Campbell (roy@cs.uiuc.edu)
  15.  *
  16.  * Funded by: NSF TAPESTRY Grant No. 1-5-30035, NASA ICLASS Grant 
  17.  *   No. 1-5-25469 and No. NSG1471 and AT&T Metronet Grant No. 1-5-37411.
  18.  */
  19. /*
  20.  * Process.c - Implementations of classes ProcessTask,
  21.  *           ProcessStatistics, Process, and IdleProcess.
  22.  *
  23.  *    $Header: Process.c,v 1.8 88/02/16 08:45:00 johnston Exp $
  24.  *    $Locker: johnston $
  25.  */
  26.  
  27. #include <task.h>
  28. #include "Assert.h"
  29. #include "Debug.h"
  30. #include "Name.h"
  31. #include "CPU.h"
  32. #include "Exception.h"
  33. #include "Process.h"
  34. #include "Clock.h"
  35. #include "Print.h"
  36.  
  37. ProcessTask::ProcessTask( Process * process, ProcessEntry entry, void * argp,
  38.               int preemptable, char * procName )
  39.     : ( CatName( MakeName( "ProcessTask", this ),
  40.              CatName( " for ", procName ) ) )
  41. {
  42.     Debug("%s::ctor: entry (*0x%08x)(0x%08x).\n", getName(), entry, argp);
  43.     Assert(entry != 0);
  44.  
  45.     /*
  46.      * Initialize.
  47.      */
  48.     ProcessTask::process = process;
  49.     Assert(preemptable == 0);
  50.     ProcessTask::preemptable = preemptable;
  51.  
  52.     /*
  53.      * Initially we're stopped.
  54.      * Eventually we'll be put on a CPU and started.
  55.      * When that happens, we call the specified procedure (with argument).
  56.      */
  57.     Debug("%s::ctor: sleeping.\n", getName());
  58.     sleep();
  59.     Debug("%s::ctor: calling (*0x%08x)(0x%08x).\n", getName(), entry, argp);
  60.     int result = (*entry)(argp);
  61.     Debug("%s::ctor: (*0x%08x)(0x%08x) returned %d.\n",
  62.         getName(), entry, argp, result);
  63.  
  64.     /*
  65.      * Terminate ourself:
  66.      *    Disallow preemption.
  67.      *    Send the TerminateVector to the CPU we're running on.
  68.      *    Delay, waiting for the Exception handler to delete us.
  69.      */
  70.     (void) setPreemptable( 0 );
  71.     Assert(process != 0);
  72.     Assert(process->cpu != 0);
  73.     process->cpu->interrupt( TerminateVector );
  74.     Debug("%s::ctor: waiting.\n", getName());
  75.     for (;;)
  76.         delay(1);
  77.     NotReached();
  78. }
  79.  
  80. char *
  81. ProcessTask::getName()
  82. {
  83.     return (t_name);
  84. }
  85.  
  86. int
  87. ProcessTask::isPreemptable()
  88. {
  89.     return (preemptable);
  90. }
  91.  
  92. int
  93. ProcessTask::setPreemptable( int flag )
  94. {
  95.     int mask = BlockClock();
  96.     int oldFlag = preemptable;
  97.     preemptable = flag;
  98.     UnblockClock( mask );
  99.     return ( oldFlag );
  100. }
  101.  
  102. ProcessStatistics::ProcessStatistics( Process * p )
  103. {
  104.     process = p;
  105.     runCount = 0;
  106.     runTime = 0;
  107.     lastRun = 0;
  108. }
  109.  
  110. void
  111. ProcessStatistics::print()
  112. {
  113.     Print( "%s ends %d ticks, dispatched %d times, total run time %d ticks.\n",
  114.         process->getName(), clock, runCount, runTime );
  115. }
  116.  
  117. Process::Process(ProcessEntry entry, void * argp, int preemptable, char * name)
  118.     : ( name ? name : MakeName( "Process", this ) )
  119. {
  120.     /*
  121.      * Enter critical section.
  122.      */
  123.     int mask = 0;
  124.     int flag = IsAProcessTask(thistask);
  125.     if ( flag )
  126.         mask = ((ProcessTask *) thistask)->setPreemptable(0);
  127.  
  128.     Debug("%s::ctor: entry (*0x%08x)(0x%08x) (%spreemptable).\n",
  129.         getName(), entry, argp, (preemptable ? "" : "not "));
  130.     Assert(entry != 0);
  131.  
  132.     /*
  133.      * Initialize and create ProcessTask (last to avoid a race with it).
  134.      * Initially the ProcessTask is not preemptable.
  135.      */
  136.     statistics = new ProcessStatistics( this );
  137.     cpu = 0;
  138.     schedulerInfo = 0;
  139.     quantum = RunToCompletion;
  140.     processTask = new ProcessTask( this, entry, argp, 0, getName() );
  141.     Assert(processTask != 0);
  142.  
  143.     /*
  144.      * Wait for the ProcessTask to go to sleep before returning.
  145.      * This avoids a race condition in which the Process might
  146.      * be woken up before it was asleep.
  147.      */
  148.     while ( processTask->rdstate() == RUNNING )
  149.         thistask->delay( 0 );
  150.     Debug("%s::ctor: process task %s.\n",
  151.         getName(), processTask->getName());
  152.     processTask->setPreemptable(preemptable);
  153.  
  154.     /*
  155.      * Leave critical section.
  156.      */
  157.     if (flag)
  158.         (void) ((ProcessTask *) thistask)->setPreemptable(mask);
  159. }
  160.  
  161. void
  162. Process::setQuantum( int q )
  163. {
  164.     Assert((q == RunToCompletion) || (q > 0));
  165.     quantum = q;
  166. }
  167.  
  168. int
  169. Process::getQuantum()
  170. {
  171.     return (quantum);
  172. }
  173.  
  174. int
  175. Process::getState()
  176. {
  177.     Assert(processTask != 0);
  178.     return (processTask->rdstate());
  179. }
  180.  
  181. Process::~Process()
  182. {
  183.     /*
  184.      * Get rid of the ProcessTask and the scheduler info.
  185.      */
  186.     Debug("%s::dtor: state %d.\n", getName(), getState());
  187.     Assert(getState() == IDLE);
  188.     processTask->cancel(0);
  189.     Assert(getState() == TERMINATED);
  190.     delete processTask;
  191.     if (schedulerInfo != 0)
  192.         delete schedulerInfo;
  193.  
  194.     /*
  195.      * Print and delete statistics.
  196.      * We don't update here because we must have been previously
  197.      * stopped, at which time the statistics were updated.
  198.      */
  199.     Assert(statistics != 0);
  200.     statistics->print();
  201.     delete statistics;
  202. }
  203.  
  204. void
  205. Process::stop()
  206. {
  207.     /*
  208.      * Stop the ProcessTask.
  209.      * Clear the CPU (because we're not running anymore).
  210.      */
  211.     Assert(cpu != 0);
  212.     Assert(processTask != 0);
  213.     Debug("%s::stop %s on %s.\n",
  214.         getName(), processTask->getName(), cpu->getName());
  215.     Assert(getState() == RUNNING);
  216.     cpu = 0;
  217.  
  218.     /*
  219.      * Update statistics.
  220.      */
  221.     Assert(statistics != 0);
  222.     Assert(clock >= statistics->lastRun);
  223.     statistics->runTime += (clock - statistics->lastRun);
  224.     processTask->sleep();
  225. }
  226.  
  227. void
  228. Process::start(CPU * cpu)
  229. {
  230.     /*
  231.      * Update statistics.
  232.      */
  233.     Assert(statistics != 0);
  234.     statistics->runCount++;
  235.     statistics->lastRun = clock;
  236.  
  237.     /*
  238.      * Set the CPU we're running on.
  239.      * Start the ProcessTask.
  240.      */
  241.     Assert(cpu != 0);
  242.     Debug("%s::start %s on %s.\n",
  243.         getName(), processTask->getName(), cpu->getName());
  244.     Assert(getState() == IDLE);
  245.     Assert(cpu->managerRunning());
  246.     Process::cpu = cpu;
  247.     processTask->delay(0);
  248.     Assert(getState() == RUNNING);
  249. }
  250.  
  251. int
  252. IdleProcessEntry(void * vcpu)
  253. {
  254.     CPU * cpu = (CPU *) vcpu;
  255.     Assert(cpu != 0);
  256.     Debug("IdleProcessEntry(%s).\n", cpu->getName());
  257.  
  258.     // Set CPU IdleException.
  259.     IdleException * idleException = new IdleException();
  260.     Assert(idleException != 0);
  261.     Debug("IdleProcessEntry: set vector %d to %s on %s.\n",
  262.         IdleVector, idleException->getName(), cpu->getName());
  263.     cpu->setException(IdleVector,idleException);
  264.  
  265.     /*
  266.      * Continually check the scheduler to see if there is a "real" Process
  267.      * which could be run.  If there is one, send the IdleVector.
  268.      * Relinquish each time around the loop to avoid starving other tasks.
  269.      */
  270.     for (;;) {
  271.         if (!cpu->getScheduler()->isEmpty()) {
  272.             Debug("IdleProcessEntry: send %d to %s.\n",
  273.                 IdleVector, cpu->getName());
  274.             cpu->interrupt(IdleVector);
  275.         }
  276.         thistask->delay(1);
  277.     }
  278.     NotReached();
  279.     return (0);
  280. }
  281.  
  282. IdleProcess::IdleProcess(CPU * cpu, char * name)
  283.     : ( (ProcessEntry) IdleProcessEntry,
  284.         (void *) cpu, 0,
  285.         ( name ? name : MakeName( "IdleProcess", this ) ) )
  286. {
  287.     /*
  288.      * We have nothing further to do.
  289.      */
  290.     Debug("%s::ctor for %s (%s).\n",
  291.         getName(), cpu->getName(), processTask->getName());
  292. }
  293.